package offical.baseClass

/**
 * 定义集合内交换元素位置的扩展函数
 */
fun <T> MutableList<T>.swap(index1: Int, index2: Int): MutableList<T> {
    val temp = this[index1]
    this[index1] = this[index2]
    this[index2] = temp
    return this
}


open class A

open class B : A()

fun A.a() {
    println("a")
}

fun B.a() {
    println("b")
}

/**
 * 扩展函数
 * 扩展不能真正的修改他们所扩展的类
 * 不是根据接收者类型的虚方法。 这意味着调用的扩展函数是由函数调用所在的表达式的类型来决定的， 而不是由表达式运行时求值结果决定的
 */
fun printA(a: A) {
    a.a()
}

/**
 * 一个类定义有一个成员函数和一个扩展函数，而这两个函数又有相同的接收者类型、相同的名字并且都适用给定的参数，
 * 这种情况总是取成员函数
 */
class ExtendFunction {
    fun foo() {
        println("member")
    }
}

fun ExtendFunction.foo() {
    println("extend")
}

/**
 * 可空接收者
 */
fun Any?.toString(): String {
    if (this == null) return "null"
    return toString()
}

/**
 * 扩展属性
 * 必须提供getter
 * 由于扩展没有实际的将成员插入类中，因此对扩展属性来说幕后字段是无效的
 * 扩展属性不能有初始化器
 * 他们的行为只能由显式提供的 getters/setters 定义
 */
val <T> List<T>.lastIndex: Int
    get() = size - 1


class MyClass{

    companion object
}

/**
 * 伴生对象的扩展
 * 就像伴生对象的其他普通成员，只需用类名作为限定符去调用他们
 */
fun MyClass.Companion.foo(){
    println("---Companion------")
}


class C{ //扩展接收者
    fun bar(){
        println("c-->bar")
    }
}

/**
 * 在一个类内部你可以为另一个类声明扩展
 * 其中的对象成员可以无需通过限定符访问
 * 扩展声明所在的类的实例称为 分发接收者，扩展方法调用所在的接收者类型的实例称为 扩展接收者
 * 对于分发接收者和扩展接收者的成员名字冲突的情况，扩展接收者优先，引用分发接收者成员可以使用this@D
 *
 */
class D{ //分发接收者

    fun bar(){
        println("d-->bar")
    }

    fun C.foo(){
        bar()
        this@D.bar()
    }

}



fun main(args: Array<String>) {
    val intList = mutableListOf(22, 33, 44)
    intList.swap(0, 2).forEach(::println)

    printA(B())  //a

    ExtendFunction().foo()

    println(intList.lastIndex)

    MyClass.foo()

}

